import { Guid } from "../Utils/Guid";
import { IncomingMessage } from "./InComingMessage";
import { OutgoingMessage } from "./OutgoingMessage";


/**
 * 
 * 辅助通道
 * @en  /// Side channels provide an alternative mechanism of sending/receiving data from Unity
    /// to Python that is outside of the traditional machine learning loop. ML-Agents provides
    /// some specific implementations of side channels, but users can create their own.
    ///
    /// To create your own, you'll need to create two, new mirrored classes, one in Unity (by
    /// extending <see cref="SideChannel"/>) and another in Python by extending a Python class
    /// also called SideChannel. Then, within your project, use
    /// <see cref="SideChannelManager.RegisterSideChannel"/> and
    /// <see cref="SideChannelManager.UnregisterSideChannel"/> to register and unregister your
    /// custom side channel.

    @zh 侧通道提供了一种从 Unity 发送/接收数据到 Python 的替代机制，该机制位于传统机器学习循环之外。ML-Agents 提供了一些特定的侧通道实现，但用户可以创建自己的侧通道。
    要创建自己的侧通道，您需要创建两个新的镜像类，一个在 Unity 中（通过扩展 <see cref="SideChannel"/>）, 另一个在 Python 中通过扩展一个名为 SideChannel 的 Python 类。
    然后，在项目中使用 <see cref="SideChannelManager.RegisterSideChannel"/> 和 <see cref="SideChannelManager.UnregisterSideChannel"/> 来注册和注销您的自定义侧通道。
 */
export abstract class SideChannel {

    /**
     * 
        @en The list of messages (byte arrays) that need to be sent to Python via the communicator.
        Should only ever be read and cleared by a ICommunicator object.

        @zh 需要通过通信器发送到 Python 的消息（字节数组）列表。只能由 ICommunicator 对象读取和清除。
     */
    messageQueue = new Array<Uint8Array>();


    channelId: Guid = Guid.empty();

    processMessage(data: Uint8Array): void {
        const incomingMsg = new IncomingMessage(data);
        this.onMessageReceived(incomingMsg);
    }

    /**
     * @en Is called by the communicator every time a message is received from Python by the SideChannel.
     * Can be called multiple times per simulation step if multiple messages were sent.
     * 
     * @zh 每次从 Python 通过侧通道接收到消息时，通信器都会调用此方法。如果发送了多条消息，则可以在每个模拟步骤中多次调用。
     * @param msg The incoming message.
     */
    abstract onMessageReceived(msg: IncomingMessage): void;

    /**
     * @en
     * Queues a message to be sent to Python during the next simulation step.
     * 
     * @zh
     * 将消息排队以在下一个模拟步骤期间发送到 Python。
     * @param msg  The byte array of data to be sent to Python
     */
    queueMessageToSend(msg: OutgoingMessage): void {
        this.messageQueue.push(msg.toByteArray());
    }
}